package leeon.mobile.server.bbscache;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import leeon.mobile.BBSBrowser.NetworkException;
import leeon.mobile.BBSBrowser.actions.BBSGaeCacheAction;
import leeon.mobile.BBSBrowser.models.BlockObject;
import leeon.mobile.BBSBrowser.models.BoardObject;
import leeon.mobile.server.bbscache.entity.Board;
import leeon.mobile.server.bbscache.entity.Doc;
import leeon.mobile.server.bbscache.entity.OffsetIndex;

import com.google.appengine.api.utils.SystemProperty;

public class BBSBoardService {
	
	private static final Logger logger = Logger.getLogger(BBSBoardService.class.getName());
	
	//提取url的实例
	private BBSGaeCacheAction action = new BBSGaeCacheAction();
	
	@SuppressWarnings("serial")
	static final List<BlockObject> BLOCK_LIST = new ArrayList<BlockObject>() {{
		add(new BlockObject("0", "BBS 系统 [站内]"));
		add(new BlockObject("1", "复旦大学 [本校]"));
		add(new BlockObject("2", "院系风采 [校园]"));
		add(new BlockObject("3", "电脑技术 [电脑]"));
		add(new BlockObject("4", "休闲娱乐 [休闲]"));
		add(new BlockObject("5", "文学艺术 [文艺]"));
		add(new BlockObject("6", "体育健身 [运动]"));
		add(new BlockObject("7", "感性空间 [感性]"));
		add(new BlockObject("8", "新闻信息 [新闻]"));
		add(new BlockObject("9", "学科学术 [学科]"));
		add(new BlockObject("A", "影视音乐 [影音]"));
		add(new BlockObject("B", "交易专区 [交易]"));
	}};
		//白名单
	@SuppressWarnings("serial")
	static final Map<String, String> BOARD_WHITE_LIST = new HashMap<String, String>() {{
		if (SystemProperty.applicationId.get().equals("fdubbsapp1") ||
				SystemProperty.applicationId.get().equals("fdubbsapp")) {
//1区
			put("Teacher", "121");
			put("Graduate", "115");
			put("Undergraduate", "122");
//4区
			put("Animal", "210");
			put("Auto", "217");
			put("Joke", "67");
			put("PIC", "11");
			put("Food", "73");
			put("Beauty", "233");
			put("Flower", "180");
			put("MyShow", "419");
			put("Travel", "80");			
//6区
			put("Football_WD", "103");
			put("Basketball", "98");
			put("Cycling", "255");
			put("Football_CN", "101");
			put("KeepFit", "104");
		} 
		if (SystemProperty.applicationId.get().equals("fdubbsapp2") ||
				SystemProperty.applicationId.get().equals("fdubbsapp")) {
//7区
			put("Employees", "110");
			put("Kids", "368");
			put("Marriage", "443");
			put("Pujiang", "279");
			put("Love", "117");
			put("Single", "120");
			put("Astrology", "193");
		}
		if (SystemProperty.applicationId.get().equals("fdubbsapp3") ||
				SystemProperty.applicationId.get().equals("fdubbsapp")) {
//8区
			put("News", "130");
			put("HomeDeco", "385");
			put("MobilePhone", "45");
			put("PC_Market", "189");
			put("Real_Estate", "472");
			put("Stock", "129");
//9区
			put("Military", "148");
			put("Nature", "145");
			put("History", "136");
//A区			
			put("Movie", "75");
			put("NR_Movie", "156");
			put("TV", "182");
			put("Pop", "82");
			put("Cartoon", "71");
			put("OMTV", "291");
		}
//Losers单独的应用
		if (SystemProperty.applicationId.get().equals("fdubbsapp4") ||
				SystemProperty.applicationId.get().equals("fdubbsapp")) {
			put("Losers", "523");			
		}
	}};
	static final boolean USE_WHITE_LIST = true;
	
	//转接版面的url，为了统一在一个文件中维护，放在board service中
	static String createViewForwardUrl(BlockObject b, String boardName, String bid) {
		String url = "http://";
		//根据board或者bid找到对应的fdubbsapp，然后跳转
		if ("Losers".equals(boardName) || "523".equals(bid))
			url += "fdubbsapp4.appspot.com";
		else if ("0123456".indexOf(b.getId()) != -1)
			url += "fdubbsapp1.appspot.com";
		else if ("7".indexOf(b.getId()) != -1)
			url += "fdubbsapp2.appspot.com";
		else if ("89AB".indexOf(b.getId()) != -1)
			url += "fdubbsapp3.appspot.com";
		else
			return null;
		return url;
	}
	
	//从网络刷新版面，从数据库刷新文章数的方法
	public void refreshAll() {
		clearAllBoard();//清数据
		List<BlockObject> all = fetchBoardFromNetwork();//从网络提取并保存
		CacheService.saveAllBoard(all);//刷新缓存
	}
	
	
	//刷新所有版面对象
	private List<BlockObject> fetchBoardFromNetwork() {
		try {
			logger.info("start refresh all board from network");
			List<BlockObject> all = action.allBoard();
			for (BlockObject b : all) {
				fetchBoardFromNetwork(b.getAllBoardList(), b.getId(), b.getRecommendBoardList());
			}
			logger.info("end refresh all board from network");
			return all;
		} catch (NetworkException e) {
			logger.log(Level.SEVERE, "fetch all board error from network", e);
			return null;
		}
	}

	//刷新版面时直接拿到bid,并同时update total
	private void fetchBoardFromNetwork(List<BoardObject> list, String parent, List<BoardObject> recom) {
		for (BoardObject b : list) {
			if (b.isDir()) {
				fetchBoardFromNetwork(b.getChildBoardList(), b.getName(), recom);
				saveBoardToDB(b, parent, false);
			} else {
				if (BOARD_WHITE_LIST.containsKey(b.getName())) {
					b.setId(BOARD_WHITE_LIST.get(b.getName()));//set bid
					//这里可不进行set bid操作了，可由update 统一执行 update 所有bid，或者fetchFromDB执行
					updateBoardTotalFromDB(b);// 从doc 中统计total totalG
				}
				
				//find recom
				boolean r = false;
				for (BoardObject b1 : recom) {
					if (b.getName().equals(b1.getName())) {
						r = true;break;
					}
				}
				
				//最后保存
				saveBoardToDB(b, parent, r);
			}
		}
	}
	
	//清空数据库	
	private void clearAllBoard() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Query query = pm.newQuery("select from leeon.mobile.server.bbscache.entity.Board");
			query.getFetchPlan().setFetchSize(100);
			query.deletePersistentAll();
		} finally {
			pm.close();
		}
	}
	
	//仅仅刷新缓存中，每个版面的total值
	public void refreshTotal() {
		List<BlockObject> all = CacheService.getOrCreateAll(false);
		for (BlockObject b : all) {
			refreshTotal(b.getAllBoardList());
		}
		//将all对象保存回缓存中，也可以全部从数据库读取一次
		CacheService.saveAllBoard(all);
	}
	
	private void refreshTotal(List<BoardObject> list) {
		for (BoardObject b : list) {
			if (b.isDir()) {
				refreshTotal(b.getChildBoardList());
			} else {
				if (BOARD_WHITE_LIST.containsKey(b.getName()) || !USE_WHITE_LIST) {
					updateBoardTotalFromDB(b);//更新入参
					updateBoardTotalToDB(b);//更新数据库
				}
			}
		}
	}
	
	//从数据更新每个版面的total值
	//仅仅还原到入参borad对象上，需要存入缓存还是存入数据库由调用者决定
	private void updateBoardTotalFromDB(BoardObject board) {
		logger.info("start update board total doc number:[" + board.getName() + "]");		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			//遍历数据库的所有主题帖，并找到每一个主题帖的最后一贴
			Query query = pm.newQuery("select from leeon.mobile.server.bbscache.entity.Doc where " +
					"key >= bidParam && key < bidParamM " +
					"parameters Long bidParam, Long bidParamM");
			query.getFetchPlan().setFetchSize(100);
			query.setResult("count(key)");
			int c = (Integer)query.executeWithArray(Doc.creatBoardFilter(Long.valueOf(board.getId())));

			query = pm.newQuery("select from leeon.mobile.server.bbscache.entity.Doc where " +
					"keyG >= bidParam && keyG < bidParamM " +
					"parameters Long bidParam, Long bidParamM");
			query.getFetchPlan().setFetchSize(100);
			query.setResult("count(keyG)");
			int g = (Integer)query.executeWithArray(Doc.creatBoardFilterG(Long.valueOf(board.getId())));
			
			board.setTotal(c);
			board.setTotalG(g);
			logger.info("end update board total doc number:[" + board.getName() + "], ret is :["+board.getTotal()+","+board.getTotalG()+"]");
		} finally {
			pm.close();
		}
	}
	
	private static void updateBoardTotalGFromDB(BoardObject board) {
		logger.info("start update board totalg doc number:[" + board.getName() + "]");		
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Query query = pm.newQuery("select from leeon.mobile.server.bbscache.entity.Doc where " +
					"keyG >= bidParam && keyG < bidParamM " +
					"parameters Long bidParam, Long bidParamM");
			query.getFetchPlan().setFetchSize(100);
			query.setResult("count(keyG)");
			int g = (Integer)query.executeWithArray(Doc.creatBoardFilterG(Long.valueOf(board.getId())));			
			
			board.setTotalG(g);
			logger.info("end update board totalg doc number:[" + board.getName() + "], ret is :["+board.getTotalG()+"]");
		} finally {
			pm.close();
		}
		
	}
	

	//刷新所有版面对象从数据库
	public List<BlockObject> fetchBoardFromDb() {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			//遍历数据库的所有主题帖，并找到每一个主题帖的最后一贴
			Query query = pm.newQuery("select from leeon.mobile.server.bbscache.entity.Board order by parent, name");
			query.getFetchPlan().setFetchSize(100);
				
			@SuppressWarnings("unchecked")
			List<Board> results = (List<Board>) query.execute();
			int b1 = -1;
			String parent = null;
			Map<String, BoardObject> b2 = new HashMap<String, BoardObject>();
			Map<BoardObject, Integer> b3 = new HashMap<BoardObject, Integer>();
			for (Board b : results) {
				BoardObject board = b.toBoardObject();
				if (b.getParent().length() == 1) {
					if (!b.getParent().equals(parent)) {
						parent = b.getParent();
						b1++;
						BLOCK_LIST.get(b1).getAllBoardList().clear();
						BLOCK_LIST.get(b1).getRecommendBoardList().clear();
					}					
					BLOCK_LIST.get(b1).getAllBoardList().add(board);
					if (b.isRecom()) BLOCK_LIST.get(b1).getRecommendBoardList().add(board);
					if (b.isDir()) {
						b2.put(board.getName(), board);
						b3.put(board, b1);
					}
				} else {
					if (!b.getParent().equals(parent)) {
						parent = b.getParent();
						b2.get(parent).getChildBoardList().clear();
					}
					
					b2.get(parent).getChildBoardList().add(board);
					if (b.isDir()) BLOCK_LIST.get(b3.get(b2.get(parent))).getRecommendBoardList().add(board);
				}
				if (BOARD_WHITE_LIST.containsKey(b.getName()) && b.getId() == null) {
					board.setId(BOARD_WHITE_LIST.get(b.getName()));
					b.setId(Long.valueOf(board.getId()));
					pm.makePersistent(b);
				}
			}
		} finally {
			pm.close();
		}
		return BLOCK_LIST;
	}
	
	//获取所有board的bid
	public void updateBoardId(BoardObject board) {
		try {
			//获取版面的bid
			action.boardDoc(board, false);
			updateBoardIdToDB(board);
		} catch (Exception e) {
			logger.log(Level.SEVERE, "get bid error", e);
		}
	}

	
	//同步某个版面的缓存信息到数据库
	public static void synchCacheToDB(BoardObject board) {
		board = Utils.findBoard(board.getName());
		updateBoardTotalToDB(board);
	}
	
	//同步某个版面的数据库信息到缓存
	public static void synchDBToCache(BoardObject board) {
		board = getBoardFromDB(board);
		CacheService.saveTotalForCacheBoard(board);
	}	
	
	//将某个版面的信息保存到数据库,only total
	public static void updateBoardTotalToDB(BoardObject board) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Board b = pm.getObjectById(Board.class, board.getName());
			b.setTotal(board.getTotal());
			b.setTotalG(board.getTotalG());
		} catch (JDOObjectNotFoundException e) {
			logger.severe("can't find board in db:[" + board.getName() + "]");
		} finally {
			pm.close();
		}		
	}
	
	//将某个版面的信息保存到数据库,only total
	public static void updateBoardIdToDB(BoardObject board) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Board b = pm.getObjectById(Board.class, board.getName());
			b.setId(Long.valueOf(board.getId()));
		} catch (JDOObjectNotFoundException e) {
			logger.severe("can't find board in db:[" + board.getName() + "]");
		} finally {
			pm.close();
		}		
	}
	
	//保存版面信息，所有信息
	public static void saveBoardToDB(BoardObject board, String parent, boolean recom) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Board b = Board.toBoard(board, parent, recom);
			pm.makePersistent(b);
		} finally {
			pm.close();
		}		
	}
		
	//提取版面信息，从数据库
	public static BoardObject getBoardFromDB(BoardObject board) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Board b = pm.getObjectById(Board.class, board.getName());
			return b.toBoardObject();
		} catch (JDOObjectNotFoundException e) {
			logger.severe("can't find board in db:[" + board.getName() + "]");
			return null;
		} finally {
			pm.close();
		}
	}
	
	//从数据create index
	public static OffsetIndex createOffsetIndexBoardFromDB(BoardObject board) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			//遍历数据库的所有主题帖，并找到每一个主题帖的最后一贴
			Query query = pm.newQuery("select key from leeon.mobile.server.bbscache.entity.Doc where " +
					"key >= bidParam && key < bidParamM " +
					"parameters Long bidParam, Long bidParamM order by key");
			query.getFetchPlan().setFetchSize(100);
			
			@SuppressWarnings("unchecked")
			List<Long> results = (List<Long>)query.executeWithArray(Doc.creatBoardFilter(Long.valueOf(board.getId())));
			
			OffsetIndex index = new OffsetIndex();
			int c = 0;
			for (Long key : results) {
				index.addToIndex(key);
				c++;
			}
			if (c != board.getTotal()) {//如果计数的总数和total数量不一致，可能出现了缓存total不正确的情况
				board.setTotal(c);//update total 
				updateBoardTotalGFromDB(board);//update total g
				updateBoardTotalToDB(board);//update db
				synchDBToCache(board);//update cache
			}
			return index;
		} finally {
			pm.close();
		}
	}

}
